home *** CD-ROM | disk | FTP | other *** search
- # Source Generated with Decompyle++
- # File: in.pyo (Python 2.5)
-
- from __future__ import with_statement
-
- try:
- _
- except:
- import gettext
- gettext.install('Digsby')
-
- import sys
- import time
- import re
- from common import profile
- from datetime import datetime, timedelta
- from util import soupify, Storage as S, tail, boolify, fromutc
- from path import path
- from digsby import iswidget
- from traceback import print_exc
- from logging import getLogger
- log = getLogger('logger')
- from common.message import Message
- import libxml2
-
- def get_default_logging_dir():
- lp = localprefs
- import prefs
- localprefs = lp()
- return path(localprefs['chatlogdir']) / DEFAULT_LOG_DIR_NAME / profile.username
-
- DEFAULT_LOG_DIR_NAME = u'Digsby Logs'
- LOGSIZE_PARSE_LIMIT = 15360
-
- def buddy_path(account, buddy):
- return path(account.name).joinpath(account.username, buddy.name + '_' + buddy.service)
-
- message_timestamp_fmt = '%Y-%m-%d %H:%M:%S'
- message_timestamp_fmt_OLD = '%Y-%m-%d %H:%M'
- filename_format_re = re.compile('\\d{4}-\\d{2}-\\d{2}\\..*')
- message_shorttime_fmt = '%H:%M:%S %p'
- html_header = u'<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"\n "http://www.w3.org/TR/html4/strict.dtd">\n<HTML>\n <HEAD>\n <TITLE>%(title)s</TITLE>\n <style>\n .buddy { font-weight: bold; }\n .buddy:after { content: ":" }\n\n .time {\n color: #a0a0a0;\n font-family: monaco, courier new, monospace;\n font-size: 75%%;\n }\n .time:hover { color: black; }\n\n .outgoing { background-color: #efefef; }\n .incoming { background-color: #ffffff; }\n </style>\n <script type="text/javascript">\n//<![CDATA[\n function convert_time(datetime){\n var dt = datetime.split(" ");\n var date = dt[0].split("-");\n var time = dt[1].split(":");\n var t = new Date;\n t.setUTCFullYear(date[0],date[1]-1,date[2]);\n t.setUTCHours(time[0],time[1],time[2]);\n return t.toLocaleTimeString();\n }\n\n function utc_to_local(){\n var node;\n for (var i=0; i<document.body.childNodes.length; i++){\n node = document.body.childNodes[i];\n if(node.nodeType == 1 && node.className.match("message")){\n var showtime = convert_time(node.getAttribute(\'timestamp\'));\n var newspan = \'<span class="time">(\' + showtime + \') </span>\';\n var msgnode = node;\n msgnode.innerHTML = newspan + msgnode.innerHTML;\n }\n }\n }\n//]]>\n </script>\n </HEAD>\n <BODY onload="utc_to_local()">\n'
- html_log_entry = '<div class="%(type)s message" auto="%(auto)s" timestamp="%(timestamp)s"><span class="buddy">%(buddy)s</span> <span class="msgcontent">%(message)s</span></div>\n'
-
- class Logger(object):
-
- def __init__(self, output_dir = None, log_ims = True, log_chats = True, log_widgets = False):
- self.OutputDir = output_dir
- self.OutputType = 'html'
- self.LogChats = log_chats
- self.LogIMs = log_ims
- self.LogWidgets = log_widgets
-
-
- def on_message(self, messageobj = None, convo = None):
- if not self.should_log_message(messageobj):
- return None
-
- output = self.generate_output(messageobj)
- written_size = self.write_output(output, messageobj)
-
- try:
- buddy = messageobj.conversation.buddy
- except AttributeError:
- pass
-
- buddy.increase_log_size(written_size)
-
-
- def should_log_message(self, messageobj):
- if messageobj is None:
- return False
-
- convo = messageobj.conversation
- if convo.ischat and not (self.LogChats):
- return False
- elif not (convo.ischat) and not (self.LogIMs):
- return False
- elif not (self.LogWidgets) and iswidget(convo.buddy):
- return False
- elif messageobj.buddy is None:
- return False
- elif not messageobj.buddy.protocol.should_log(messageobj):
- return False
-
- return True
-
-
- def history_for(self, account, buddy):
- log.info('history_for(%r, %r)', account, buddy)
- files = self.logfiles_for(account, buddy)
- log.info('%d %s log files found', len(files), self.OutputType)
- if not files:
- return iter([])
-
- files.sort(reverse = True)
- return history_from_files(files, 'html')
-
-
- def logsize(self, account, buddy):
- return sum((lambda .0: for f in .0:
- f.size)(self.logfiles_for(account, buddy)))
-
-
- def logfiles_for(self, account, buddy):
- logdir = self.pathfor(account, buddy)
- if not logdir.exists():
- return []
-
- return list((lambda .0: for f in .0:
- if filename_format_re.match(f.name):
- fcontinue)(logdir.files('*.' + self.OutputType)))
-
-
- def pathfor(self, account, buddy):
- return self.OutputDir.joinpath(buddy_path(account, buddy))
-
-
- def set_outputdir(self, val):
- self.output_dir = None if val is not None else get_default_logging_dir()
-
-
- def get_outputdir(self):
- return self.output_dir
-
- OutputDir = property(get_outputdir, set_outputdir, doc = 'where to write logs')
-
- def write_output(self, output, messageobj):
- convo = messageobj.conversation
- proto = convo.protocol
- datefilename = fromutc(messageobj.timestamp).date().isoformat()
- pathelems = (buddy_path(proto, convo.buddy), datefilename)
- p = path(path(self.OutputDir).joinpath(*pathelems) + '.' + self.OutputType)
- if not p.parent.exists():
- p.parent.makedirs()
-
- written_size = 0
- if not p.exists():
- header = globals()['generate_header_' + self.OutputType](messageobj, self.output_encoding)
- written_size += len(header)
- p.write_bytes(header)
-
- written_size += len(output)
- p.write_bytes(output, append = p.exists())
- return written_size
-
-
- def generate_output(self, messageobj):
- return globals()['generate_output_' + self.OutputType](messageobj, self.output_encoding)
-
- output_encoding = 'utf-8'
-
-
- def generate_header_html(messageobj, encoding):
- c = messageobj.conversation
- datefmt = messageobj.timestamp.date().isoformat()
- if c.ischat:
- title = 'Chat in %s on %s' % (c.name, datefmt)
- else:
- title = 'IM Logs with %s on %s' % (c.buddy.name, datefmt)
- return (html_header % dict(title = title.encode('xml'))).encode(encoding, 'replace')
-
-
- def generate_output_html(m, encoding = 'utf-8'):
- return (None % html_log_entry(dict = 'buddy' if m.buddy is not None else '', timestamp = m.timestamp.strftime(message_timestamp_fmt), message = m.message, type = m.type, auto = getattr(m, 'auto', False))).encode(encoding, 'replace')
-
- class_buddy = {
- 'class': 'buddy' }
- class_message = {
- 'class': 'message' }
- class_msgcontent = {
- 'class': 'msgcontent' }
-
- def message_divs(tag):
- if tag.name == 'div':
- pass
- return 'message' in dict(tag.attrs).get('class', '')
-
-
- def parse_html_fast(html):
- doc = libxml2.htmlParseDoc(html, 'utf-8')
-
- try:
- divs = doc.xpathEval('//html/body/div')
- messages = []
- for div in divs:
- message_type = div.properties.content
- if 'message' not in message_type:
- continue
-
- type = message_type.replace('message', '').strip()
- if type not in ('incoming', 'outgoing'):
- log.critical('got an unknown message type: %s', type)
- raise ValueError('unknown message type')
-
- props = div.properties
- (auto, timestamp, buddyname, message) = (None, None, None, None)
- while props:
- name = props.name
- value = props.content
- if name == 'auto':
- auto = boolify(value)
- elif name == 'timestamp':
- timestamp = parse_timestamp(value)
-
- props = props.get_next()
- child = div.children
- while child:
- props = child.properties
- if props is not None:
- attrs = props.content
- if attrs == 'buddy':
- buddyname = child.content.decode('utf-8')
- elif attrs == 'msgcontent':
- message = child.serialize().decode('utf-8')
-
-
- child = child.next
- if all((lambda .0: for a in .0:
- a is not None)((auto, timestamp, buddyname, message))):
- messages.append(Message(buddy = S(name = buddyname), timestamp = timestamp, message = message, type = type, auto = auto))
- continue
- raise ValueError('not all attributes could be parsed: %r' % ((auto, timestamp, buddyname, message),))
-
- log.info('parse_html_fast with %d bytes returning %d messages', len(html), len(messages))
- return messages
- finally:
- doc.freeDoc()
-
-
-
- def parse_html_slow(html):
- soup = soupify(html, markupMassage = ((br_re, (lambda m: '<br />')),))
- messages = []
- strptime = datetime.strptime
- for div in soup.findAll(message_divs):
-
- try:
- buddyname = div.findAll('span', class_buddy)[0].renderContents(None)
- timestamp = parse_timestamp(div['timestamp'])
- message = div.findAll('span', class_msgcontent)[0].renderContents(None)
- type = div['class'].replace('message', '').strip()
- auto = boolify(div.get('auto', 'false'))
- except Exception:
- print_exc()
- continue
-
- messages.append(Message(buddy = S(name = buddyname), timestamp = timestamp, message = message, type = type, auto = auto))
-
- log.info('parse_html_slow with %d bytes returning %d messages', len(html), len(messages))
- return messages
-
- USE_LIBXML2_HTML_PARSER = False
-
- def parse_html(html, last_parsed = [
- None,
- None]):
- digest = hash(html)
- (msghash, oldmessages) = last_parsed
- if msghash == digest:
- return oldmessages
-
- if not USE_LIBXML2_HTML_PARSER or sys.platform == 'darwin':
- messages = parse_html_slow(html)
- else:
-
- try:
- messages = parse_html_fast(html)
- except Exception:
- messages = parse_html_slow(html)
- log.info('parsed slow: got %d messages', len(messages))
-
- last_parsed[0] = digest
- last_parsed[1] = messages
- return messages
-
-
- def parse_timestamp(timestamp):
-
- try:
- return datetime.strptime(timestamp, message_timestamp_fmt)
- except Exception:
- return datetime.strptime(timestamp, message_timestamp_fmt_OLD)
-
-
-
- def chat_path(account, room_name, *additional):
- return path(account.name).joinpath(account.username, *additional)
-
-
- def history_from_files(files, logtype = 'html', encoding = 'utf-8'):
- parse = globals()['parse_' + logtype]
- for logfile in files:
-
- try:
- bytes = tail(logfile, LOGSIZE_PARSE_LIMIT, encoding = encoding)
- except Exception:
- print_exc()
- continue
-
- for msg in reversed(parse(bytes)):
- yield msg
-
- if len(bytes) < logfile.size:
- break
- continue
-
-
- import re
- real_br = '<br />'
- br_re = re.compile('<br\\s*/?>', re.IGNORECASE)
-
- brfix = lambda s: br_re.sub(real_br, s)
-